from pydantic import BaseModel, Field
from langchain.prompts.chat import ChatMessagePromptTemplate
# from configs import logger, log_verbose
from loguru import logger
from typing import List, Tuple, Dict, Union
import uuid
import httpx
from startup import API_SERVER
import json
from server.utils import BaseResponse


class History(BaseModel):
    """
    对话历史
    可从dict生成，如
    h = History(**{"role":"user","content":"你好"})
    也可转换为tuple，如
    h.to_msy_tuple = ("human", "你好")
    """
    role: str = Field(...)
    content: str = Field(...)

    def to_msg_tuple(self):
        return "ai" if self.role == "assistant" else "human", self.content

    def to_msg_template(self, is_raw=True) -> ChatMessagePromptTemplate:
        role_maps = {
            "ai": "assistant",
            "human": "user",
        }
        role = role_maps.get(self.role, self.role)
        if is_raw:  # 当前默认历史消息都是没有input_variable的文本。
            content = "{% raw %}" + self.content + "{% endraw %}"
        else:
            content = self.content

        return ChatMessagePromptTemplate.from_template(
            content,
            "jinja2",
            role=role,
        )

    @classmethod
    def from_data(cls, h: Union[List, Tuple, Dict]) -> "History":
        if isinstance(h, (list, tuple)) and len(h) >= 2:
            h = cls(role=h[0], content=h[1])
        elif isinstance(h, dict):
            h = cls(**h)

        return h


# 定义一个用于生成用户交互日志记录的函数，输入参数包括当前时间、用户ID、查询内容、回答内容和操作说明，
# 函数内部将这些参数按照特定格式拼接成一个日志字符串，并返回该字符串。
def log_content(uid, query, answer, instruction, request_id, city="", district="", chat_type=""):
    # 定义日志格式
    format_string = "uid:\"{uid}\", query:\"{query}\", response:\"{answer}\", instruction:\"{instruction}\", request_id:\"{request_id}\", city:\"{city}\", district:\"{district}\", chat_type:\"{chat_type}\""

    # 记录日志
    logger.info(format_string.format(uid=uid, query=query, answer=answer, instruction=instruction, request_id=request_id, city=city, district=district, chat_type=chat_type))


def generate_request_id():
    return str(uuid.uuid4())

# 定义纯llm对话方法
async def llm_chat(query: str, prompt_name: str, temperature: float):
    try:
        async with httpx.AsyncClient() as client:
            url = f"http://127.0.0.1:{API_SERVER['port']}/chat/chat"
            payload = {
                "query": query,
                "prompt_name": prompt_name,
                "temperature": temperature
            }
            response = await client.post(url=url, json=payload)
            if response.status_code == 200:
                async for line in response.aiter_lines():
                    if line.startswith('data: '):
                        data = json.loads(line[len('data: '):])
                        print(data)
                        return data.get("text")
                    elif line == ":ping":
                        # This is a ping message, we can ignore it
                        continue
            else:
                return BaseResponse(code=50004, msg="Failed to recognize intent.")
    except Exception as e:
        logger.error(f"Failed to recognize intent: {e}")
        return BaseResponse(code=50004, msg="Failed to recognize intent.")

# 定义纯llm对话方法
async def summarize_chat(query: str, prompt_name: str, temperature: float, answer: str = None):
    try:
        async with httpx.AsyncClient() as client:
            url = f"http://127.0.0.1:{API_SERVER['port']}/chat/summarize_chat"
            payload = {
                "query": query,
                "answer": answer,
                "prompt_name": prompt_name,
                "temperature": temperature
            }
            response = await client.post(url=url, json=payload)
            if response.status_code == 200:
                async for line in response.aiter_lines():
                    if line.startswith('data: '):
                        data = json.loads(line[len('data: '):])
                        print(data)
                        return data.get("text")
                    elif line == ":ping":
                        # This is a ping message, we can ignore it
                        continue
            else:
                return BaseResponse(code=50004, msg="Failed to recognize intent.")
    except Exception as e:
        logger.error(f"Failed to recognize intent: {e}")
        return BaseResponse(code=50004, msg="Failed to recognize intent.")
